/**
 * @author tanghailan
 * @date 2021年11月08日 17:42
 */
public class BlockQueue<T> {
  Object[] queue;
  private volatile int head, tail, size;
  private final int cap;
  private final Object lock = new Object();

  public BlockQueue(int cap) {
    this.cap = cap;
    queue = new Object[cap];
  }

  public void offer(T t) throws InterruptedException {
    synchronized (lock) {
      if (size == cap) {
        lock.wait();
      }

      queue[tail++] = t;
      tail %= cap;
      size++;

      lock.notify();
    }
  }

  public T poll() throws InterruptedException {
    T res;
    synchronized (lock) {
      if (size == 0) {
        lock.wait();
      }

      res = (T) queue[head++];
      head %= cap;
      size--;

      lock.notify();
    }
    return res;
  }
}
